package cn.com.demo.config;

import cn.com.demo.filter.MyTokenAuthFilter;
import cn.com.demo.filter.MyTokenLoginFilter;
import cn.com.demo.service.MyUserDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    MyUserDetailService userDetailService;
    @Autowired
    private MyPasswordEncoder myPasswordEncoder;
    @Autowired
    private MyLogoutHandler myLogoutHandler;
    @Autowired
    private MyTokenConfig myTokenConfig;
    @Autowired
    private MyUnAuthEntryPoint myUnAuthEntryPoint;
//   关闭basic 认证
//    @Override
//    protected void configure(HttpSecurity http) throws Exception {
//        // 关闭basic认证
//        // http.authorizeRequests().anyRequest().authenticated().and().httpBasic().disable();
//    }
// 基于配置文件的认证
//    @Override
//    protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
//        // 密码加密
//        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
//        String password = bCryptPasswordEncoder.encode("admin1");
//        // 配置认证信息
//        authenticationManagerBuilder.inMemoryAuthentication().passwordEncoder(bCryptPasswordEncoder).withUser("admin").password(password).roles("roleA");
//    }

    /**
     * JWT
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                // 未授权访问
                .exceptionHandling()
                    // 认证失败
                    .authenticationEntryPoint(myUnAuthEntryPoint)
                    // 鉴权失败
                    .defaultAccessDeniedHandlerFor(new MyAccessDeniedHandler(),new AntPathRequestMatcher("/**"))
                .and()
                // 关闭csrf检查，此项检查开启时可能导致过滤链被提前终止
                .csrf().disable()
//                // 资源权限
                .authorizeRequests().anyRequest().authenticated()
                //关闭basic验证
                .and().httpBasic().disable()
//                // 登录设置 (自定义认证过滤器后失效，如本例中已经定义MyTokenLoginFilter)
                .formLogin().loginProcessingUrl("/noauth/sublogin")
                .and()
//                // 退出登录设置
                .logout().logoutUrl("/noauth/logout").addLogoutHandler(myLogoutHandler)
                .and()
//                // 认证处理器
                .addFilter(new MyTokenLoginFilter(authenticationManager(), myTokenConfig))
//                // 授权处理器
                        .addFilter(new MyTokenAuthFilter(authenticationManager(),myTokenConfig));
    }
    @Override
    public void configure(WebSecurity webSecurity) throws Exception {
        // 忽略鉴权及认证配置，配置此项的地址将不会被security过滤连过滤（包括认证、登出等）
        webSecurity.ignoring().antMatchers("/auth/**");
    }
    @Override
    protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
        // 设置用户查询服务及密码处理器
       //  authenticationManagerBuilder.userDetailsService(userDetailService).passwordEncoder(myPasswordEncoder);
        // 当手动注入AuthenticationProvider时，需要做如下声明
        authenticationManagerBuilder.authenticationProvider(daoAuthenticationProvider());

    }

    /**
     * 通过手动注入DaoAuthenticationProvider 覆盖 hideUserNotFoundExceptions的值，UserNameNotFoundException 可正常抛出
     * 手动注入此bea需要指定UserDetailsService （Spring bean.afterPropertiesSet() ）
     * @return
     */
    @Bean
    public DaoAuthenticationProvider daoAuthenticationProvider(){
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        // 手动覆盖如下参数可取消在configure(AuthenticationManagerBuilder authenticationManagerBuilder) 中的配置,但需要指明此provider
        provider.setHideUserNotFoundExceptions(false);
        provider.setUserDetailsService(userDetailService);
        provider.setPasswordEncoder(myPasswordEncoder);
        return provider;
    }
//    @Bean
//    public BCryptPasswordEncoder bCryptPasswordEncoder(){
//        return new BCryptPasswordEncoder();
//    }
}
